agora inbox for [email protected]help / color / mirror / Atom feed
Some shared memory chunks are allocated even if related processes won't start 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ 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; 2381+ 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] 2381+ messages in thread
* [PATCH v2 2/4] pg_upgrade: bump minimum supported version to v10 @ 2026-04-17 18:20 Nathan Bossart <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Nathan Bossart @ 2026-04-17 18:20 UTC (permalink / raw) --- doc/src/sgml/ref/pgupgrade.sgml | 2 +- src/bin/pg_upgrade/check.c | 157 +---------------------- src/bin/pg_upgrade/controldata.c | 12 +- src/bin/pg_upgrade/exec.c | 23 ---- src/bin/pg_upgrade/file.c | 164 ------------------------- src/bin/pg_upgrade/multixact_rewrite.c | 11 +- src/bin/pg_upgrade/pg_upgrade.c | 31 +---- src/bin/pg_upgrade/pg_upgrade.h | 29 ----- src/bin/pg_upgrade/relfilenumber.c | 37 +----- src/bin/pg_upgrade/version.c | 127 ------------------- 10 files changed, 16 insertions(+), 577 deletions(-) diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml index 38ca09b423c..c4ed75211db 100644 --- a/doc/src/sgml/ref/pgupgrade.sgml +++ b/doc/src/sgml/ref/pgupgrade.sgml @@ -67,7 +67,7 @@ PostgreSQL documentation </para> <para> - <application>pg_upgrade</application> supports upgrades from 9.2.X and later to the current + <application>pg_upgrade</application> supports upgrades from 10.X and later to the current major release of <productname>PostgreSQL</productname>, including snapshot and beta releases. </para> diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c index 5a7afe62eab..0813cef2729 100644 --- a/src/bin/pg_upgrade/check.c +++ b/src/bin/pg_upgrade/check.c @@ -28,7 +28,6 @@ static void check_for_incompatible_polymorphics(ClusterInfo *cluster); static void check_for_tables_with_oids(ClusterInfo *cluster); static void check_for_not_null_inheritance(ClusterInfo *cluster); static void check_for_gist_inet_ops(ClusterInfo *cluster); -static void check_for_pg_role_prefix(ClusterInfo *cluster); static void check_for_new_tablespace_dir(void); static void check_for_user_defined_encoding_conversions(ClusterInfo *cluster); static void check_for_unicode_update(ClusterInfo *cluster); @@ -128,26 +127,6 @@ static DataTypesUsageChecks data_types_usage_checks[] = .threshold_version = ALL_VERSIONS }, - /* - * 9.3 -> 9.4 Fully implement the 'line' data type in 9.4, which - * previously returned "not enabled" by default and was only functionally - * enabled with a compile-time switch; as of 9.4 "line" has a different - * on-disk representation format. - */ - { - .status = gettext_noop("Checking for incompatible \"line\" data type"), - .report_filename = "tables_using_line.txt", - .base_query = - "SELECT 'pg_catalog.line'::pg_catalog.regtype AS oid", - .report_text = - gettext_noop("Your installation contains the \"line\" data type in user tables.\n" - "This data type changed its internal and input/output format\n" - "between your old and new versions so this\n" - "cluster cannot currently be upgraded. You can\n" - "drop the problem columns and restart the upgrade.\n"), - .threshold_version = 903 - }, - /* * pg_upgrade only preserves these system values: pg_class.oid pg_type.oid * pg_enum.oid @@ -209,30 +188,6 @@ static DataTypesUsageChecks data_types_usage_checks[] = .threshold_version = 1500 }, - /* - * It's no longer allowed to create tables or views with "unknown"-type - * columns. We do not complain about views with such columns, because - * they should get silently converted to "text" columns during the DDL - * dump and reload; it seems unlikely to be worth making users do that by - * hand. However, if there's a table with such a column, the DDL reload - * will fail, so we should pre-detect that rather than failing - * mid-upgrade. Worse, if there's a matview with such a column, the DDL - * reload will silently change it to "text" which won't match the on-disk - * storage (which is like "cstring"). So we *must* reject that. - */ - { - .status = gettext_noop("Checking for invalid \"unknown\" user columns"), - .report_filename = "tables_using_unknown.txt", - .base_query = - "SELECT 'pg_catalog.unknown'::pg_catalog.regtype AS oid", - .report_text = - gettext_noop("Your installation contains the \"unknown\" data type in user tables.\n" - "This data type is no longer allowed in tables, so this cluster\n" - "cannot currently be upgraded. You can drop the problem columns\n" - "and restart the upgrade.\n"), - .threshold_version = 906 - }, - /* * PG 12 changed the 'sql_identifier' type storage to be based on name, * not varchar, which breaks on-disk format for existing data. So we need @@ -255,23 +210,6 @@ static DataTypesUsageChecks data_types_usage_checks[] = .threshold_version = 1100 }, - /* - * JSONB changed its storage format during 9.4 beta, so check for it. - */ - { - .status = gettext_noop("Checking for incompatible \"jsonb\" data type in user tables"), - .report_filename = "tables_using_jsonb.txt", - .base_query = - "SELECT 'pg_catalog.jsonb'::pg_catalog.regtype AS oid", - .report_text = - gettext_noop("Your installation contains the \"jsonb\" data type in user tables.\n" - "The internal format of \"jsonb\" changed during 9.4 beta so this\n" - "cluster cannot currently be upgraded. You can drop the problem \n" - "columns and restart the upgrade.\n"), - .threshold_version = MANUAL_CHECK, - .version_hook = jsonb_9_4_check_applicable - }, - /* * PG 12 removed types abstime, reltime, tinterval. */ @@ -712,20 +650,6 @@ check_and_dump_old_cluster(void) if (GET_MAJOR_VERSION(old_cluster.major_version) <= 1800) check_for_gist_inet_ops(&old_cluster); - /* - * Pre-PG 10 allowed tables with 'unknown' type columns and non WAL logged - * hash indexes - */ - if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906) - { - if (user_opts.check) - old_9_6_invalidate_hash_indexes(&old_cluster, true); - } - - /* 9.5 and below should not have roles starting with pg_ */ - if (GET_MAJOR_VERSION(old_cluster.major_version) <= 905) - check_for_pg_role_prefix(&old_cluster); - /* * While not a check option, we do this now because this is the only time * the old server is running. @@ -772,20 +696,6 @@ check_new_cluster(void) * system boundaries. */ check_hard_link(TRANSFER_MODE_SWAP); - - /* - * There are a few known issues with using --swap to upgrade from - * versions older than 10. For example, the sequence tuple format - * changed in v10, and the visibility map format changed in 9.6. - * While such problems are not insurmountable (and we may have to - * deal with similar problems in the future, anyway), it doesn't - * seem worth the effort to support swap mode for upgrades from - * long-unsupported versions. - */ - if (GET_MAJOR_VERSION(old_cluster.major_version) < 1000) - pg_fatal("Swap mode can only upgrade clusters from PostgreSQL version %s and later.", - "10"); - break; } @@ -831,10 +741,6 @@ issue_warnings_and_set_wal_level(void) */ start_postmaster(&new_cluster, true); - /* Reindex hash indexes for old < 10.0 */ - if (GET_MAJOR_VERSION(old_cluster.major_version) <= 906) - old_9_6_invalidate_hash_indexes(&new_cluster, false); - report_extension_updates(&new_cluster); stop_postmaster(false); @@ -892,9 +798,9 @@ check_cluster_versions(void) * upgrades */ - if (GET_MAJOR_VERSION(old_cluster.major_version) < 902) + if (GET_MAJOR_VERSION(old_cluster.major_version) < 10) pg_fatal("This utility can only upgrade from PostgreSQL version %s and later.", - "9.2"); + "10"); /* Only current PG version is supported as a target */ if (GET_MAJOR_VERSION(new_cluster.major_version) != GET_MAJOR_VERSION(PG_VERSION_NUM)) @@ -1569,12 +1475,10 @@ check_for_incompatible_polymorphics(ClusterInfo *cluster) ", 'array_cat(anyarray,anyarray)'" ", 'array_prepend(anyelement,anyarray)'"); - if (GET_MAJOR_VERSION(cluster->major_version) >= 903) appendPQExpBufferStr(&old_polymorphics, ", 'array_remove(anyarray,anyelement)'" ", 'array_replace(anyarray,anyelement,anyelement)'"); - if (GET_MAJOR_VERSION(cluster->major_version) >= 905) appendPQExpBufferStr(&old_polymorphics, ", 'array_position(anyarray,anyelement)'" ", 'array_position(anyarray,anyelement,integer)'" @@ -1870,63 +1774,6 @@ check_for_gist_inet_ops(ClusterInfo *cluster) check_ok(); } -/* - * check_for_pg_role_prefix() - * - * Versions older than 9.6 should not have any pg_* roles - */ -static void -check_for_pg_role_prefix(ClusterInfo *cluster) -{ - PGresult *res; - PGconn *conn = connectToServer(cluster, "template1"); - int ntups; - int i_roloid; - int i_rolname; - FILE *script = NULL; - char output_path[MAXPGPATH]; - - prep_status("Checking for roles starting with \"pg_\""); - - snprintf(output_path, sizeof(output_path), "%s/%s", - log_opts.basedir, - "pg_role_prefix.txt"); - - res = executeQueryOrDie(conn, - "SELECT oid AS roloid, rolname " - "FROM pg_catalog.pg_roles " - "WHERE rolname ~ '^pg_'"); - - ntups = PQntuples(res); - i_roloid = PQfnumber(res, "roloid"); - i_rolname = PQfnumber(res, "rolname"); - for (int rowno = 0; rowno < ntups; rowno++) - { - if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %m", output_path); - fprintf(script, "%s (oid=%s)\n", - PQgetvalue(res, rowno, i_rolname), - PQgetvalue(res, rowno, i_roloid)); - } - - PQclear(res); - - PQfinish(conn); - - if (script) - { - fclose(script); - pg_log(PG_REPORT, "fatal"); - pg_fatal("Your installation contains roles starting with \"pg_\".\n" - "\"pg_\" is a reserved prefix for system roles. The cluster\n" - "cannot be upgraded until these roles are renamed.\n" - "A list of roles starting with \"pg_\" is in the file:\n" - " %s", output_path); - } - else - check_ok(); -} - /* * Callback function for processing results of query for * check_for_user_defined_encoding_conversions()'s UpgradeTask. If the query diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c index cffcd4b0eba..8188355240f 100644 --- a/src/bin/pg_upgrade/controldata.c +++ b/src/bin/pg_upgrade/controldata.c @@ -602,14 +602,12 @@ get_control_data(ClusterInfo *cluster) /* verify that we got all the mandatory pg_control data */ if (!got_xid || !got_oid || !got_multi || !got_oldestxid || - (!got_oldestmulti && - cluster->controldata.cat_ver >= MULTIXACT_FORMATCHANGE_CAT_VER) || + !got_oldestmulti || !got_mxoff || (!live_check && !got_nextxlogfile) || !got_float8_pass_by_value || !got_align || !got_blocksz || !got_largesz || !got_walsz || !got_walseg || !got_ident || !got_index || !got_toast || - (!got_large_object && - cluster->controldata.ctrl_ver >= LARGE_OBJECT_SIZE_PG_CONTROL_VER) || + !got_large_object || !got_date_is_int || !got_data_checksum_version || (!got_default_char_signedness && cluster->controldata.cat_ver >= DEFAULT_CHAR_SIGNEDNESS_CAT_VER)) @@ -630,8 +628,7 @@ get_control_data(ClusterInfo *cluster) if (!got_multi) pg_log(PG_REPORT, " latest checkpoint next MultiXactId"); - if (!got_oldestmulti && - cluster->controldata.cat_ver >= MULTIXACT_FORMATCHANGE_CAT_VER) + if (!got_oldestmulti) pg_log(PG_REPORT, " latest checkpoint oldest MultiXactId"); if (!got_oldestxid) @@ -670,8 +667,7 @@ get_control_data(ClusterInfo *cluster) if (!got_toast) pg_log(PG_REPORT, " maximum TOAST chunk size"); - if (!got_large_object && - cluster->controldata.ctrl_ver >= LARGE_OBJECT_SIZE_PG_CONTROL_VER) + if (!got_large_object) pg_log(PG_REPORT, " large-object chunk size"); if (!got_date_is_int) diff --git a/src/bin/pg_upgrade/exec.c b/src/bin/pg_upgrade/exec.c index e1de61f36ee..479557abdcc 100644 --- a/src/bin/pg_upgrade/exec.c +++ b/src/bin/pg_upgrade/exec.c @@ -55,16 +55,7 @@ get_bin_version(ClusterInfo *cluster) if (sscanf(cmd_output, "%*s %*s %d.%d", &v1, &v2) < 1) pg_fatal("could not get pg_ctl version output from %s", cmd); - if (v1 < 10) - { - /* old style, e.g. 9.6.1 */ - cluster->bin_version = v1 * 10000 + v2 * 100; - } - else - { - /* new style, e.g. 10.1 */ cluster->bin_version = v1 * 10000; - } } @@ -353,17 +344,7 @@ check_data_dir(ClusterInfo *cluster) check_single_dir(pg_data, "pg_subtrans"); check_single_dir(pg_data, PG_TBLSPC_DIR); check_single_dir(pg_data, "pg_twophase"); - - /* pg_xlog has been renamed to pg_wal in v10 */ - if (GET_MAJOR_VERSION(cluster->major_version) <= 906) - check_single_dir(pg_data, "pg_xlog"); - else check_single_dir(pg_data, "pg_wal"); - - /* pg_clog has been renamed to pg_xact in v10 */ - if (GET_MAJOR_VERSION(cluster->major_version) <= 906) - check_single_dir(pg_data, "pg_clog"); - else check_single_dir(pg_data, "pg_xact"); } @@ -404,10 +385,6 @@ check_bin_dir(ClusterInfo *cluster, bool check_versions) */ get_bin_version(cluster); - /* pg_resetxlog has been renamed to pg_resetwal in version 10 */ - if (GET_MAJOR_VERSION(cluster->bin_version) <= 906) - check_exec(cluster->bindir, "pg_resetxlog", check_versions); - else check_exec(cluster->bindir, "pg_resetwal", check_versions); if (cluster == &new_cluster) diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c index 5b276008614..af82c0de490 100644 --- a/src/bin/pg_upgrade/file.c +++ b/src/bin/pg_upgrade/file.c @@ -20,12 +20,8 @@ #include <linux/fs.h> #endif -#include "access/visibilitymapdefs.h" #include "common/file_perm.h" #include "pg_upgrade.h" -#include "storage/bufpage.h" -#include "storage/checksum.h" -#include "storage/checksum_impl.h" /* @@ -196,166 +192,6 @@ linkFile(const char *src, const char *dst, } -/* - * rewriteVisibilityMap() - * - * Transform a visibility map file, copying from src to dst. - * schemaName/relName are relation's SQL name (used for error messages only). - * - * In versions of PostgreSQL prior to catversion 201603011, PostgreSQL's - * visibility map included one bit per heap page; it now includes two. - * When upgrading a cluster from before that time to a current PostgreSQL - * version, we could refuse to copy visibility maps from the old cluster - * to the new cluster; the next VACUUM would recreate them, but at the - * price of scanning the entire table. So, instead, we rewrite the old - * visibility maps in the new format. That way, the all-visible bits - * remain set for the pages for which they were set previously. The - * all-frozen bits are never set by this conversion; we leave that to VACUUM. - */ -void -rewriteVisibilityMap(const char *fromfile, const char *tofile, - const char *schemaName, const char *relName) -{ - int src_fd; - int dst_fd; - PGIOAlignedBlock buffer; - PGIOAlignedBlock new_vmbuf; - ssize_t totalBytesRead = 0; - ssize_t src_filesize; - int rewriteVmBytesPerPage; - BlockNumber new_blkno = 0; - struct stat statbuf; - - /* Compute number of old-format bytes per new page */ - rewriteVmBytesPerPage = (BLCKSZ - SizeOfPageHeaderData) / 2; - - if ((src_fd = open(fromfile, O_RDONLY | PG_BINARY, 0)) < 0) - pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %m", - schemaName, relName, fromfile); - - if (fstat(src_fd, &statbuf) != 0) - pg_fatal("error while copying relation \"%s.%s\": could not stat file \"%s\": %m", - schemaName, relName, fromfile); - - if ((dst_fd = open(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, - pg_file_create_mode)) < 0) - pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %m", - schemaName, relName, tofile); - - /* Save old file size */ - src_filesize = statbuf.st_size; - - /* - * Turn each visibility map page into 2 pages one by one. Each new page - * has the same page header as the old one. If the last section of the - * last page is empty, we skip it, mostly to avoid turning one-page - * visibility maps for small relations into two pages needlessly. - */ - while (totalBytesRead < src_filesize) - { - ssize_t bytesRead; - char *old_cur; - char *old_break; - char *old_blkend; - PageHeaderData pageheader; - bool old_lastblk; - - if ((bytesRead = read(src_fd, buffer.data, BLCKSZ)) != BLCKSZ) - { - if (bytesRead < 0) - pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %m", - schemaName, relName, fromfile); - else - pg_fatal("error while copying relation \"%s.%s\": partial page found in file \"%s\"", - schemaName, relName, fromfile); - } - - totalBytesRead += BLCKSZ; - old_lastblk = (totalBytesRead == src_filesize); - - /* Save the page header data */ - memcpy(&pageheader, buffer.data, SizeOfPageHeaderData); - - /* - * These old_* variables point to old visibility map page. old_cur - * points to current position on old page. old_blkend points to end of - * old block. old_break is the end+1 position on the old page for the - * data that will be transferred to the current new page. - */ - old_cur = buffer.data + SizeOfPageHeaderData; - old_blkend = buffer.data + bytesRead; - old_break = old_cur + rewriteVmBytesPerPage; - - while (old_break <= old_blkend) - { - char *new_cur; - bool empty = true; - bool old_lastpart; - - /* First, copy old page header to new page */ - memcpy(new_vmbuf.data, &pageheader, SizeOfPageHeaderData); - - /* Rewriting the last part of the last old page? */ - old_lastpart = old_lastblk && (old_break == old_blkend); - - new_cur = new_vmbuf.data + SizeOfPageHeaderData; - - /* Process old page bytes one by one, and turn it into new page. */ - while (old_cur < old_break) - { - uint8 byte = *(uint8 *) old_cur; - uint16 new_vmbits = 0; - int i; - - /* Generate new format bits while keeping old information */ - for (i = 0; i < BITS_PER_BYTE; i++) - { - if (byte & (1 << i)) - { - empty = false; - new_vmbits |= - VISIBILITYMAP_ALL_VISIBLE << (BITS_PER_HEAPBLOCK * i); - } - } - - /* Copy new visibility map bytes to new-format page */ - new_cur[0] = (char) (new_vmbits & 0xFF); - new_cur[1] = (char) (new_vmbits >> 8); - - old_cur++; - new_cur += BITS_PER_HEAPBLOCK; - } - - /* If the last part of the last page is empty, skip writing it */ - if (old_lastpart && empty) - break; - - /* Set new checksum for visibility map page, if enabled */ - if (new_cluster.controldata.data_checksum_version != PG_DATA_CHECKSUM_OFF) - ((PageHeader) new_vmbuf.data)->pd_checksum = - pg_checksum_page(new_vmbuf.data, new_blkno); - - errno = 0; - if (write(dst_fd, new_vmbuf.data, BLCKSZ) != BLCKSZ) - { - /* if write didn't set errno, assume problem is no disk space */ - if (errno == 0) - errno = ENOSPC; - pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %m", - schemaName, relName, tofile); - } - - /* Advance for next new page */ - old_break += rewriteVmBytesPerPage; - new_blkno++; - } - } - - /* Clean up */ - close(dst_fd); - close(src_fd); -} - void check_file_clone(void) { diff --git a/src/bin/pg_upgrade/multixact_rewrite.c b/src/bin/pg_upgrade/multixact_rewrite.c index 823984ec8f3..c45b3183684 100644 --- a/src/bin/pg_upgrade/multixact_rewrite.c +++ b/src/bin/pg_upgrade/multixact_rewrite.c @@ -25,10 +25,7 @@ static void RecordMultiXactMembers(SlruSegState *members_writer, * 32-bit offsets to the current format. * * Multixids in the range [from_multi, to_multi) are read from the old - * cluster, and written in the new format. An important edge case is that if - * from_multi == to_multi, this initializes the new pg_multixact files in the - * new format without trying to open any old files. (We rely on that when - * upgrading from PostgreSQL version 9.2 or below.) + * cluster, and written in the new format. * * Returns the new nextOffset value; the caller should set it in the new * control file. The new members always start from offset 1, regardless of @@ -42,6 +39,7 @@ rewrite_multixacts(MultiXactId from_multi, MultiXactId to_multi) SlruSegState *members_writer; char dir[MAXPGPATH] = {0}; bool prev_multixid_valid = false; + OldMultiXactReader *old_reader; /* * The range of valid multi XIDs is unchanged by the conversion (they are @@ -63,10 +61,6 @@ rewrite_multixacts(MultiXactId from_multi, MultiXactId to_multi) * Convert old multixids, if needed, by reading them one-by-one from the * old cluster. */ - if (to_multi != from_multi) - { - OldMultiXactReader *old_reader; - old_reader = AllocOldMultiXactRead(old_cluster.pgdata, old_cluster.controldata.chkpnt_nxtmulti, old_cluster.controldata.chkpnt_nxtmxoff); @@ -113,7 +107,6 @@ rewrite_multixacts(MultiXactId from_multi, MultiXactId to_multi) } FreeOldMultiXactReader(old_reader); - } /* Write the final 'next' offset to the last SLRU page */ RecordMultiXactOffset(offsets_writer, to_multi, diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index 2127d297bfe..e5d7920c1b1 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -714,13 +714,6 @@ create_new_objects(void) end_progress_output(); check_ok(); - /* - * We don't have minmxids for databases or relations in pre-9.3 clusters, - * so set those after we have restored the schema. - */ - if (GET_MAJOR_VERSION(old_cluster.major_version) <= 902) - set_frozenxids(true); - /* update new_cluster info now that we have objects in the databases */ get_db_rel_and_slot_infos(&new_cluster); } @@ -777,10 +770,7 @@ copy_xact_xlog_xid(void) * Copy old commit logs to new data dir. pg_clog has been renamed to * pg_xact in post-10 clusters. */ - copy_subdir_files(GET_MAJOR_VERSION(old_cluster.major_version) <= 906 ? - "pg_clog" : "pg_xact", - GET_MAJOR_VERSION(new_cluster.major_version) <= 906 ? - "pg_clog" : "pg_xact"); + copy_subdir_files("pg_xact", "pg_xact"); prep_status("Setting oldest XID for new cluster"); exec_prog(UTILITY_LOG_FILE, NULL, true, true, @@ -809,7 +799,6 @@ copy_xact_xlog_xid(void) check_ok(); /* Copy or convert pg_multixact files */ - Assert(new_cluster.controldata.cat_ver >= MULTIXACT_FORMATCHANGE_CAT_VER); Assert(new_cluster.controldata.cat_ver >= MULTIXACTOFFSET_FORMATCHANGE_CAT_VER); if (old_cluster.controldata.cat_ver >= MULTIXACTOFFSET_FORMATCHANGE_CAT_VER) { @@ -844,25 +833,7 @@ copy_xact_xlog_xid(void) * Determine the range of multixacts to convert. */ nxtmulti = old_cluster.controldata.chkpnt_nxtmulti; - if (old_cluster.controldata.cat_ver >= MULTIXACT_FORMATCHANGE_CAT_VER) - { - /* Versions 9.3 - 18: convert all multixids */ oldstMulti = old_cluster.controldata.chkpnt_oldstMulti; - } - else - { - /* - * In PostgreSQL 9.2 and below, multitransactions were only used - * for row locking, and as such don't need to be preserved during - * upgrade. In that case, we utilize rewrite_multixacts() just to - * initialize new, empty files in the new format. - * - * It's important that the oldest multi is set to the latest value - * used by the old system, so that multixact.c returns the empty - * set for multis that might be present on disk. - */ - oldstMulti = nxtmulti; - } /* handle wraparound */ if (nxtmulti < FirstMultiXactId) nxtmulti = FirstMultiXactId; diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 1d767bbda2d..5a0d2045be5 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -101,19 +101,6 @@ extern char *output_files[]; #endif -/* - * The format of visibility map was changed with this 9.6 commit. - */ -#define VISIBILITY_MAP_FROZEN_BIT_CAT_VER 201603011 - -/* - * pg_multixact format changed in 9.3 commit 0ac5ad5134f2769ccbaefec73844f85, - * ("Improve concurrency of foreign key locking") which also updated catalog - * version to this value. pg_upgrade behavior depends on whether old and new - * server versions are both newer than this, or only the new one is. - */ -#define MULTIXACT_FORMATCHANGE_CAT_VER 201301231 - /* * MultiXactOffset was changed from 32-bit to 64-bit in version 19, at this * catalog version. pg_multixact files need to be converted when upgrading @@ -121,17 +108,6 @@ extern char *output_files[]; */ #define MULTIXACTOFFSET_FORMATCHANGE_CAT_VER 202512091 -/* - * large object chunk size added to pg_controldata, - * commit 5f93c37805e7485488480916b4585e098d3cc883 - */ -#define LARGE_OBJECT_SIZE_PG_CONTROL_VER 942 - -/* - * change in JSONB format during 9.4 beta - */ -#define JSONB_FORMAT_CHANGE_CAT_VER 201409291 - /* * The control file was changed to have the default char signedness, * commit 44fe30fdab6746a287163e7cc093fd36cda8eb92 @@ -429,8 +405,6 @@ void copyFileByRange(const char *src, const char *dst, const char *schemaName, const char *relName); void linkFile(const char *src, const char *dst, const char *schemaName, const char *relName); -void rewriteVisibilityMap(const char *fromfile, const char *tofile, - const char *schemaName, const char *relName); void check_file_clone(void); void check_copy_file_range(void); void check_hard_link(transferMode transfer_mode); @@ -500,10 +474,7 @@ unsigned int str2uint(const char *str); /* version.c */ -bool jsonb_9_4_check_applicable(ClusterInfo *cluster); bool protocol_negotiation_supported(const ClusterInfo *cluster); -void old_9_6_invalidate_hash_indexes(ClusterInfo *cluster, - bool check_mode); void report_extension_updates(ClusterInfo *cluster); diff --git a/src/bin/pg_upgrade/relfilenumber.c b/src/bin/pg_upgrade/relfilenumber.c index d5088447e0d..ec2ff7acb21 100644 --- a/src/bin/pg_upgrade/relfilenumber.c +++ b/src/bin/pg_upgrade/relfilenumber.c @@ -18,7 +18,7 @@ #include "pg_upgrade.h" static void transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace, char *new_tablespace); -static void transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit); +static void transfer_relfile(FileNameMap *map, const char *type_suffix); /* * The following set of sync_queue_* functions are used for --swap to reduce @@ -496,25 +496,10 @@ transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace, char *new_tablespace) { int mapnum; - bool vm_must_add_frozenbit = false; - - /* - * Do we need to rewrite visibilitymap? - */ - if (old_cluster.controldata.cat_ver < VISIBILITY_MAP_FROZEN_BIT_CAT_VER && - new_cluster.controldata.cat_ver >= VISIBILITY_MAP_FROZEN_BIT_CAT_VER) - vm_must_add_frozenbit = true; /* --swap has its own subroutine */ if (user_opts.transfer_mode == TRANSFER_MODE_SWAP) { - /* - * We don't support --swap to upgrade from versions that require - * rewriting the visibility map. We should've failed already if - * someone tries to do that. - */ - Assert(!vm_must_add_frozenbit); - do_swap(maps, size, old_tablespace, new_tablespace); return; } @@ -525,13 +510,13 @@ transfer_single_new_db(FileNameMap *maps, int size, strcmp(maps[mapnum].old_tablespace, old_tablespace) == 0) { /* transfer primary file */ - transfer_relfile(&maps[mapnum], "", vm_must_add_frozenbit); + transfer_relfile(&maps[mapnum], ""); /* * Copy/link any fsm and vm files, if they exist */ - transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit); - transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit); + transfer_relfile(&maps[mapnum], "_fsm"); + transfer_relfile(&maps[mapnum], "_vm"); } } } @@ -540,12 +525,10 @@ transfer_single_new_db(FileNameMap *maps, int size, /* * transfer_relfile() * - * Copy or link file from old cluster to new one. If vm_must_add_frozenbit - * is true, visibility map forks are converted and rewritten, even in link - * mode. + * Copy or link file from old cluster to new one. */ static void -transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_frozenbit) +transfer_relfile(FileNameMap *map, const char *type_suffix) { char old_file[MAXPGPATH]; char new_file[MAXPGPATH]; @@ -604,14 +587,6 @@ transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_fro /* Copying files might take some time, so give feedback. */ pg_log(PG_STATUS, "%s", old_file); - if (vm_must_add_frozenbit && strcmp(type_suffix, "_vm") == 0) - { - /* Need to rewrite visibility map format */ - pg_log(PG_VERBOSE, "rewriting \"%s\" to \"%s\"", - old_file, new_file); - rewriteVisibilityMap(old_file, new_file, map->nspname, map->relname); - } - else switch (user_opts.transfer_mode) { case TRANSFER_MODE_CLONE: diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c index 047670d4acb..9e83d4659be 100644 --- a/src/bin/pg_upgrade/version.c +++ b/src/bin/pg_upgrade/version.c @@ -12,22 +12,6 @@ #include "fe_utils/string_utils.h" #include "pg_upgrade.h" -/* - * version_hook functions for check_for_data_types_usage in order to determine - * whether a data type check should be executed for the cluster in question or - * not. - */ -bool -jsonb_9_4_check_applicable(ClusterInfo *cluster) -{ - /* JSONB changed its storage format during 9.4 beta */ - if (GET_MAJOR_VERSION(cluster->major_version) == 904 && - cluster->controldata.cat_ver < JSONB_FORMAT_CHANGE_CAT_VER) - return true; - - return false; -} - /* * Older servers can't support newer protocol versions, so their connection * strings will need to lock max_protocol_version to 3.0. @@ -46,117 +30,6 @@ protocol_negotiation_supported(const ClusterInfo *cluster) return (GET_MAJOR_VERSION(cluster->major_version) >= 1100); } -/* - * old_9_6_invalidate_hash_indexes() - * 9.6 -> 10 - * Hash index binary format has changed from 9.6->10.0 - */ -void -old_9_6_invalidate_hash_indexes(ClusterInfo *cluster, bool check_mode) -{ - int dbnum; - FILE *script = NULL; - bool found = false; - char *output_path = "reindex_hash.sql"; - - prep_status("Checking for hash indexes"); - - for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++) - { - PGresult *res; - bool db_used = false; - int ntups; - int rowno; - int i_nspname, - i_relname; - DbInfo *active_db = &cluster->dbarr.dbs[dbnum]; - PGconn *conn = connectToServer(cluster, active_db->db_name); - - /* find hash indexes */ - res = executeQueryOrDie(conn, - "SELECT n.nspname, c.relname " - "FROM pg_catalog.pg_class c, " - " pg_catalog.pg_index i, " - " pg_catalog.pg_am a, " - " pg_catalog.pg_namespace n " - "WHERE i.indexrelid = c.oid AND " - " c.relam = a.oid AND " - " c.relnamespace = n.oid AND " - " a.amname = 'hash'" - ); - - ntups = PQntuples(res); - i_nspname = PQfnumber(res, "nspname"); - i_relname = PQfnumber(res, "relname"); - for (rowno = 0; rowno < ntups; rowno++) - { - found = true; - if (!check_mode) - { - if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) - pg_fatal("could not open file \"%s\": %m", output_path); - if (!db_used) - { - PQExpBufferData connectbuf; - - initPQExpBuffer(&connectbuf); - appendPsqlMetaConnect(&connectbuf, active_db->db_name); - fputs(connectbuf.data, script); - termPQExpBuffer(&connectbuf); - db_used = true; - } - fprintf(script, "REINDEX INDEX %s.%s;\n", - quote_identifier(PQgetvalue(res, rowno, i_nspname)), - quote_identifier(PQgetvalue(res, rowno, i_relname))); - } - } - - PQclear(res); - - if (!check_mode && db_used) - { - /* mark hash indexes as invalid */ - PQclear(executeQueryOrDie(conn, - "UPDATE pg_catalog.pg_index i " - "SET indisvalid = false " - "FROM pg_catalog.pg_class c, " - " pg_catalog.pg_am a, " - " pg_catalog.pg_namespace n " - "WHERE i.indexrelid = c.oid AND " - " c.relam = a.oid AND " - " c.relnamespace = n.oid AND " - " a.amname = 'hash'")); - } - - PQfinish(conn); - } - - if (script) - fclose(script); - - if (found) - { - report_status(PG_WARNING, "warning"); - if (check_mode) - pg_log(PG_WARNING, "\n" - "Your installation contains hash indexes. These indexes have different\n" - "internal formats between your old and new clusters, so they must be\n" - "reindexed with the REINDEX command. After upgrading, you will be given\n" - "REINDEX instructions."); - else - pg_log(PG_WARNING, "\n" - "Your installation contains hash indexes. These indexes have different\n" - "internal formats between your old and new clusters, so they must be\n" - "reindexed with the REINDEX command. The file\n" - " %s\n" - "when executed by psql by the database superuser will recreate all invalid\n" - "indexes; until then, none of these indexes will be used.", - output_path); - } - else - check_ok(); -} - /* * Callback function for processing results of query for * report_extension_updates()'s UpgradeTask. If the query returned any rows, -- 2.50.1 (Apple Git-155) --CT89ko5pLUrsvFtH Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v2-0003-psql-bump-minimum-supported-version-to-v10.patch ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-22 15:01 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-22 15:01 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing DROP PROPERTY GRAPH to hit the default case and error out with "unsupported object class". The bug only manifests when an event trigger is active, because that is what calls these functions. This commit adds the missing cases so that DROP PROPERTY GRAPH, DROP PROPERTY GRAPH IF EXISTS, and DROP SCHEMA CASCADE on schemas containing property graphs all work correctly when event triggers are present. It also adds test cases that create an event trigger and then exercise DROP PROPERTY GRAPH and DROP SCHEMA CASCADE with property graphs. Author: Bertrand Drouvot <[email protected]> --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 36 +++++++ .../regress/sql/create_property_graph.sql | 36 +++++++ 3 files changed, 165 insertions(+) 54.5% src/backend/catalog/ 24.2% src/test/regress/expected/ 21.1% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..942a1294b15 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -922,5 +922,41 @@ ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; NOTICE: relation "g1" does not exist, skipping DROP PROPERTY GRAPH IF EXISTS g1; NOTICE: property graph "g1" does not exist, skipping +-- Test DROP PROPERTY GRAPH with dependency resolution +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; + count +------- + 0 +(1 row) + +DROP TABLE dpg_t1, dpg_t2; +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to table dpg_schema.t +drop cascades to property graph dpg_schema.g +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..857098dadc8 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -360,6 +360,42 @@ ALTER PROPERTY GRAPH g1 ADD VERTEX TABLES (t1 KEY (a)); -- error ALTER PROPERTY GRAPH IF EXISTS g1 SET SCHEMA create_property_graph_tests_2; DROP PROPERTY GRAPH IF EXISTS g1; + +-- Test DROP PROPERTY GRAPH with dependency resolution + +RESET search_path; +CREATE FUNCTION dpg_evt_func() RETURNS event_trigger +LANGUAGE plpgsql AS $$ +BEGIN END; +$$; + +CREATE EVENT TRIGGER dpg_evt ON ddl_command_end EXECUTE FUNCTION dpg_evt_func(); + +CREATE TABLE dpg_t1 (id int PRIMARY KEY, val text); +CREATE TABLE dpg_t2 (id int PRIMARY KEY, src int, dst int); +CREATE PROPERTY GRAPH dpg_test + VERTEX TABLES (dpg_t1 KEY (id) LABEL person PROPERTIES (val AS name)) + EDGE TABLES (dpg_t2 KEY (id) + SOURCE KEY (src) REFERENCES dpg_t1 (id) + DESTINATION KEY (dst) REFERENCES dpg_t1 (id) + LABEL knows); +DROP PROPERTY GRAPH dpg_test; + +-- table survives graph drop +SELECT COUNT(*) FROM dpg_t1; +DROP TABLE dpg_t1, dpg_t2; + +-- Test DROP SCHEMA CASCADE with property graphs inside +CREATE SCHEMA dpg_schema; +SET search_path = dpg_schema; +CREATE TABLE t (id int PRIMARY KEY); +CREATE PROPERTY GRAPH g VERTEX TABLES (t KEY (id)); +RESET search_path; +DROP SCHEMA dpg_schema CASCADE; + +DROP EVENT TRIGGER dpg_evt; +DROP FUNCTION dpg_evt_func; + DROP ROLE regress_graph_user1, regress_graph_user2; -- leave remaining objects behind for pg_upgrade/pg_dump tests -- 2.34.1 --s/7v445LwpBnK/Gl-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types and in create_property_graph.sql covering all property graph object types. A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 +++++++++++++++++++ .../expected/create_property_graph.out | 78 ++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 10 +- .../regress/sql/create_property_graph.sql | 23 +++++ src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 6 +- 7 files changed, 238 insertions(+), 2 deletions(-) 14.7% src/backend/catalog/ 75.5% src/test/regress/expected/ 9.7% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/create_property_graph.out b/src/test/regress/expected/create_property_graph.out index bc9a596ec89..eb9e17fb727 100644 --- a/src/test/regress/expected/create_property_graph.out +++ b/src/test/regress/expected/create_property_graph.out @@ -752,6 +752,84 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* type | create_property_graph_tests | g2 | create_property_graph_tests.g2 (21 rows) +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + obj | ident | addr +----------------------------------------------------------+----------------------------------------------------------------------------+---------------------------------------------------------------------------- + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + edge e of property graph gt | ("property graph element",,,"e of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of edge e of property graph gt | ("property graph element label",,,"e of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,e}",{}) + label e of property graph gt | ("property graph label",,,"e of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,e}",{}) + label v1 of property graph gt | ("property graph label",,,"v1 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v1 of vertex v1 of property graph gt | ("property graph element label",,,"v1 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v1}",{}) + label v2 of property graph gt | ("property graph label",,,"v2 of create_property_graph_tests.gt") | ("property graph label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + label v2 of vertex v2 of property graph gt | ("property graph element label",,,"v2 of create_property_graph_tests.gt") | ("property graph element label","{create_property_graph_tests,gt,v2}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property a of property graph gt | ("property graph property",,,"a of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,a}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of label v1 of vertex v1 of property graph gt | ("property graph label property",,,"v1 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v1}",{}) + property b of property graph gt | ("property graph property",,,"b of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,b}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property c of property graph gt | ("property graph property",,,"c of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,c}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k1 of property graph gt | ("property graph property",,,"k1 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k1}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of label e of edge e of property graph gt | ("property graph label property",,,"e of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,e}",{}) + property k2 of property graph gt | ("property graph property",,,"k2 of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,k2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property m of property graph gt | ("property graph property",,,"m of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,m}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of label v2 of vertex v2 of property graph gt | ("property graph label property",,,"v2 of create_property_graph_tests.gt") | ("property graph label property","{create_property_graph_tests,gt,v2}",{}) + property n of property graph gt | ("property graph property",,,"n of create_property_graph_tests.gt") | ("property graph property","{create_property_graph_tests,gt,n}",{}) + type gt | (type,create_property_graph_tests,gt,create_property_graph_tests.gt) | (type,{create_property_graph_tests.gt},{}) + type gt[] | (type,create_property_graph_tests,_gt,create_property_graph_tests.gt[]) | (type,{create_property_graph_tests.gt[]},{}) + vertex v1 of property graph gt | ("property graph element",,,"v1 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v1}",{}) + vertex v2 of property graph gt | ("property graph element",,,"v2 of create_property_graph_tests.gt") | ("property graph element","{create_property_graph_tests,gt,v2}",{}) +(52 rows) + \a\t SELECT pg_get_propgraphdef('g2'::regclass); CREATE PROPERTY GRAPH create_property_graph_tests.g2 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..5e53f0b092e 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -84,7 +86,9 @@ WARNING: error for toast table column: unsupported object type "toast table col WARNING: error for view column: unsupported object type "view column" WARNING: error for materialized view column: unsupported object type "materialized view column" WARNING: error for property graph element: unsupported object type "property graph element" +WARNING: error for property graph element label: unrecognized object type "property graph element label" WARNING: error for property graph label: unsupported object type "property graph label" +WARNING: error for property graph label property: unrecognized object type "property graph label property" WARNING: error for property graph property: unsupported object type "property graph property" -- miscellaneous other errors select * from pg_get_object_address('operator of access method', '{btree,integer_ops,1}', '{int4,bool}'); @@ -593,7 +597,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +659,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/create_property_graph.sql b/src/test/regress/sql/create_property_graph.sql index 241f93df302..9608dd5c4af 100644 --- a/src/test/regress/sql/create_property_graph.sql +++ b/src/test/regress/sql/create_property_graph.sql @@ -298,6 +298,29 @@ SELECT (pg_identify_object(classid, objid, objsubid)).* refobjid = 'create_property_graph_tests.g2'::regclass ORDER BY 1, 2, 3, 4; +-- test object address functions with recursive dependency walk +-- covers all property graph object types including indirect dependents +SELECT * +FROM ( + WITH RECURSIVE deps (classid, objid, objsubid, refclassid, refobjid, refobjsubid) AS ( + SELECT classid, objid, objsubid, + refclassid, refobjid, refobjsubid + FROM pg_depend + WHERE refclassid = 'pg_class'::regclass AND + refobjid = 'create_property_graph_tests.gt'::regclass + UNION ALL + SELECT d.classid, d.objid, d.objsubid, + d.refclassid, d.refobjid, d.refobjsubid + FROM pg_depend d + JOIN deps dp ON d.refclassid = dp.classid AND d.refobjid = dp.objid AND d.refobjsubid = dp.objsubid + ) + SELECT pg_describe_object(classid, objid, objsubid) as obj, + pg_identify_object(classid, objid, objsubid) as ident, + pg_identify_object_as_address(classid, objid, objsubid) as addr + FROM deps +) s +ORDER BY obj COLLATE "C", ident::text COLLATE "C"; + \a\t SELECT pg_get_propgraphdef('g2'::regclass); SELECT pg_get_propgraphdef('g3'::regclass); diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..27109d421c7 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -67,7 +67,9 @@ DECLARE BEGIN FOR objtype IN VALUES ('toast table'), ('index column'), ('sequence column'), ('toast table column'), ('view column'), ('materialized view column'), - ('property graph element'), ('property graph label'), ('property graph property') + ('property graph element'), ('property graph element label'), + ('property graph label'), ('property graph label property'), + ('property graph property') LOOP BEGIN PERFORM pg_get_object_address(objtype, '{one}', '{}'); @@ -282,7 +284,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --R84XrR4Hgw0dH3Ec-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
* [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error @ 2026-04-23 09:27 Bertrand Drouvot <[email protected]> 0 siblings, 0 replies; 2381+ messages in thread From: Bertrand Drouvot @ 2026-04-23 09:27 UTC (permalink / raw) getObjectTypeDescription() and getObjectIdentityParts() are missing switch cases for PropgraphElementLabelRelationId and PropgraphLabelPropertyRelationId, causing them to hit the default case and error out with "unsupported object class". During DROP PROPERTY GRAPH, this manifests when an event trigger is active, because pg_event_trigger_ddl_commands() calls these functions. The same code paths are also reachable via pg_identify_object() and pg_identify_object_as_address(). This commit adds the missing cases. Test coverage is added in object_address.sql for these two catalog types via the zero-OID test that exercises pg_identify_object() and pg_identify_object_as_address(). A test in event_trigger.sql verifies that DROP PROPERTY GRAPH works correctly when an event trigger is active. Author: Bertrand Drouvot <[email protected]> Reviewed-by: Michael Paquier <[email protected]> Reviewed-by: Ashutosh Bapat <[email protected]> Discussion: https://postgr.es/m/aej1DkLwhyZWmtxJ@bdtpg --- src/backend/catalog/objectaddress.c | 93 ++++++++++++++++++++ src/test/regress/expected/event_trigger.out | 17 ++++ src/test/regress/expected/object_address.out | 4 + src/test/regress/sql/event_trigger.sql | 13 +++ src/test/regress/sql/object_address.sql | 2 + 5 files changed, 129 insertions(+) 62.4% src/backend/catalog/ 25.6% src/test/regress/expected/ 11.8% src/test/regress/sql/ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c1862809577..e2d6d8f71f6 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -4901,10 +4901,18 @@ getObjectTypeDescription(const ObjectAddress *object, bool missing_ok) appendStringInfoString(&buffer, "policy"); break; + case PropgraphElementLabelRelationId: + appendStringInfoString(&buffer, "property graph element label"); + break; + case PropgraphElementRelationId: appendStringInfoString(&buffer, "property graph element"); break; + case PropgraphLabelPropertyRelationId: + appendStringInfoString(&buffer, "property graph label property"); + break; + case PropgraphLabelRelationId: appendStringInfoString(&buffer, "property graph label"); break; @@ -6161,6 +6169,49 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphElementLabelRelationId: + { + Relation ellabelDesc; + ScanKeyData skey[1]; + SysScanDesc ellabelscan; + HeapTuple tup; + Form_pg_propgraph_element_label pgelform; + ObjectAddress oa; + + ellabelDesc = table_open(PropgraphElementLabelRelationId, AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_element_label_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + ellabelscan = systable_beginscan(ellabelDesc, + PropgraphElementLabelObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(ellabelscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for element label %u", + object->objectId); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + + pgelform = (Form_pg_propgraph_element_label) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementRelationId, pgelform->pgelelid); + + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(ellabelscan); + table_close(ellabelDesc, AccessShareLock); + break; + } + case PropgraphElementRelationId: { HeapTuple tup; @@ -6184,6 +6235,48 @@ getObjectIdentityParts(const ObjectAddress *object, break; } + case PropgraphLabelPropertyRelationId: + { + Relation lblpropDesc; + ScanKeyData skey[1]; + SysScanDesc lblpropscan; + HeapTuple tup; + Form_pg_propgraph_label_property plpform; + ObjectAddress oa; + + lblpropDesc = table_open(PropgraphLabelPropertyRelationId, + AccessShareLock); + ScanKeyInit(&skey[0], + Anum_pg_propgraph_label_property_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + + lblpropscan = systable_beginscan(lblpropDesc, PropgraphLabelPropertyObjectIndexId, + true, NULL, 1, skey); + + tup = systable_getnext(lblpropscan); + if (!HeapTupleIsValid(tup)) + { + if (!missing_ok) + elog(ERROR, "could not find tuple for label property %u", + object->objectId); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + + plpform = (Form_pg_propgraph_label_property) GETSTRUCT(tup); + + ObjectAddressSet(oa, PropgraphElementLabelRelationId, plpform->plpellabelid); + appendStringInfoString(&buffer, getObjectIdentityParts(&oa, objname, + objargs, false)); + + systable_endscan(lblpropscan); + table_close(lblpropDesc, AccessShareLock); + break; + } + case PropgraphLabelRelationId: { HeapTuple tup; diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 065f586310f..ed8d5df397e 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -173,6 +173,23 @@ NOTICE: test_event_trigger: ddl_command_end CREATE USER MAPPING alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; NOTICE: test_event_trigger: ddl_command_end ALTER DEFAULT PRIVILEGES +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE TABLE t2x (i int PRIMARY KEY, j text); +NOTICE: test_event_trigger: ddl_command_start CREATE TABLE +NOTICE: test_event_trigger: ddl_command_end CREATE TABLE +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); +NOTICE: test_event_trigger: ddl_command_end CREATE PROPERTY GRAPH +DROP PROPERTY GRAPH gx; +NOTICE: test_event_trigger: ddl_command_end DROP PROPERTY GRAPH +DROP TABLE t1x, t2x; +NOTICE: test_event_trigger: ddl_command_end DROP TABLE -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; ERROR: permission denied to change owner of event trigger "regress_event_trigger" diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 97227d67a54..729c3537f25 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -593,7 +593,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace @@ -653,6 +655,8 @@ ORDER BY objects.classid, objects.objid, objects.objsubid; ("(""parameter ACL"",,,)")|("(""parameter ACL"",,)")|NULL ("(""property graph element"",,,)")|("(""property graph element"",,)")|NULL ("(""property graph label"",,,)")|("(""property graph label"",,)")|NULL +("(""property graph element label"",,,)")|("(""property graph element label"",,)")|NULL ("(""property graph property"",,,)")|("(""property graph property"",,)")|NULL +("(""property graph label property"",,,)")|("(""property graph label property"",,)")|NULL -- restore normal output mode \a\t diff --git a/src/test/regress/sql/event_trigger.sql b/src/test/regress/sql/event_trigger.sql index 32e9bb58c5e..271f443378b 100644 --- a/src/test/regress/sql/event_trigger.sql +++ b/src/test/regress/sql/event_trigger.sql @@ -143,6 +143,19 @@ create user mapping for regress_evt_user server useless_server; alter default privileges for role regress_evt_user revoke delete on tables from regress_evt_user; +-- DROP PROPERTY GRAPH should work with event trigger in place +CREATE TABLE t1x (a int PRIMARY KEY, b text); +CREATE TABLE t2x (i int PRIMARY KEY, j text); + +CREATE PROPERTY GRAPH gx + VERTEX TABLES ( + t1x KEY (a) LABEL l1 PROPERTIES (b AS p1), + t2x KEY (i) LABEL l2 PROPERTIES (j AS p1) +); + +DROP PROPERTY GRAPH gx; +DROP TABLE t1x, t2x; + -- alter owner to non-superuser should fail alter event trigger regress_event_trigger owner to regress_evt_user; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 1bbe9457c1c..620dacf1045 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -282,7 +282,9 @@ WITH objects (classid, objid, objsubid) AS (VALUES ('pg_parameter_acl'::regclass, 0, 0), -- no parameter ACL ('pg_policy'::regclass, 0, 0), -- no policy ('pg_propgraph_element'::regclass, 0, 0), -- no property graph element + ('pg_propgraph_element_label'::regclass, 0, 0), -- no property graph element label ('pg_propgraph_label'::regclass, 0, 0), -- no property graph label + ('pg_propgraph_label_property'::regclass, 0, 0), -- no property graph label property ('pg_propgraph_property'::regclass, 0, 0), -- no property graph property ('pg_publication'::regclass, 0, 0), -- no publication ('pg_publication_namespace'::regclass, 0, 0), -- no publication namespace -- 2.34.1 --gtUR827Uq8d5gVsQ-- ^ permalink raw reply [nested|flat] 2381+ messages in thread
end of thread, other threads:[~2026-04-23 09:27 UTC | newest] Thread overview: 2381+ 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-17 18:20 [PATCH v2 2/4] pg_upgrade: bump minimum supported version to v10 Nathan Bossart <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-22 15:01 [PATCH v1] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 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 v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v2] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH v3] Fix DROP PROPERTY GRAPH "unsupported object class" error Bertrand Drouvot <[email protected]> 2026-04-23 09:27 [PATCH 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 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 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 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 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 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 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 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 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